package vis;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Collections;
import java.util.Vector;

import util.Util;

import logic.Line;
import logic.PointD;
import logic.Polygon;
import anim.Animation;
import anim.DummyFrame;
import anim.MoveObject;
import anim.ResetHighlight;
import anim.SetHighlight;
import anim.SetLabelText;
import anim.SetSweep;
import anim.SetVisibility;

public class GPolygon extends Polygon implements Drawable {
	private Color color = Color.blue;
	private boolean visible = true;
	private Color hlColor = new Color(255, 255, 0, 128);
	private boolean hl = false;
	
	public GPolygon() {
		super();
	}
	
	@Override
	public void draw(Graphics2D g) {
		
		if(hl && pts.size() > 2)
		{
			int[] posX = new int[pts.size()];
			int[] posY = new int[pts.size()];
			
			for(int i = 0; i < pts.size(); ++i)
			{
				posX[i] = (int) pts.get(i).getX();
				posY[i] = (int) pts.get(i).getY();
			}
			g.setColor(hlColor);
			g.fillPolygon(posX, posY, pts.size());
		}
		
		for(Line l : edges)
		{
			if(l instanceof GLine)
				((GLine)l).draw(g);
		}
		
		if(closure != null)
			if(closure instanceof GLine)
				((GLine)closure).draw(g);
		
		for(PointD p : pts)
		{
			if(p instanceof GPoint)
				((GPoint)p).draw(g);
		}
	}

	@Override
	public Color getColor() {
		return color;
	}

	@Override
	public void resetHighlight() {
		hl = false;
		
		for(GLine l : edges)
		{
			l.resetHighlight();
		}
		if(closure != null) closure.resetHighlight();
	}

	@Override
	public void setColor(Color c) {
		color = c;
	}

	@Override
	public void setHighlight(Color c) {
		hlColor = c;
		hl = true;
		
		for(GLine l : edges)
		{
			l.setHighlight(c);
		}
		if(closure != null) closure.setHighlight(c);
	}

	@Override
	public boolean isVisible() {
		return visible;
	}

	@Override
	public void setPosition(double x, double y) {
	}

	@Override
	public void setVisible(boolean vis) {
		visible = vis;
	}

	@Override
	public double getPosX() {
		return 0;
	}

	@Override
	public double getPosY() {
		return 0;
	}
	
	public Vector<GLine> upperHull = new Vector<GLine>();
	public Vector<GLine> lowerHull = new Vector<GLine>();
	
	public static final int UPPER = 1;
	public static final int LOWER = 2;
	
	public boolean checkXMonotone(Animation anim, TextLabel label)
	{
		if(pts.size() < 3) return false;
		
		double dir = pts.get(1).getX() - pts.get(0).getX();
		int turns = 0;
		boolean monotone = true;
		
		anim.addFrame(new MoveObject(label, pts.get(0), false), 2);
		anim.addFrame(new SetLabelText(label, "Pocetna tacka"), 0);
		anim.addFrame(new DummyFrame(), 10);
		
		upperHull.clear();
		lowerHull.clear();
		
		Vector<GLine> tempList = new Vector<GLine>();
		int pos = 0;
		
		GLine lseg = new GLine(pts.get(0), pts.get(1));
		lseg.makeRight();
		lseg.setParent(this);
		tempList.add(lseg);
		
		for(int i = 1; i < pts.size(); ++i)
		{
			GPoint current = pts.get(i);
			GPoint next = pts.get((i + 1) % pts.size());
			double ndir = next.getX() - current.getX();
			
			anim.addFrame(new MoveObject(label, pts.get(i), false), 0);
			anim.addFrame(new ResetHighlight(label), 0);
			
			
			
			if(Math.signum(dir) == Math.signum(ndir) || dir == 0.0)
			{
				anim.addFrame(new SetLabelText(label, "Isti X-smijer"), 0);
			}
			else
			{
				turns++;
				if(turns == 1)
				{
					anim.addFrame(new SetHighlight(label, Color.BLUE), 0);
					anim.addFrame(new SetLabelText(label, "Prvi okret"), 0);
					anim.addFrame(new DummyFrame(), 20);
					
					if(next.getY() < current.getY()) // Bili smo u gornjem
					{
						for(Line l : tempList) l.meta1 = UPPER;
						upperHull.addAll(tempList);
						tempList.clear();
						pos = LOWER;
					}
					else
					{
						for(Line l : tempList) l.meta1 = LOWER;
						lowerHull.addAll(tempList);	// Bili smo u donjem;
						tempList.clear();
						pos = UPPER;
					}
				}
				else if(turns == 2)
				{
					anim.addFrame(new SetHighlight(label, Color.BLUE), 0);
					anim.addFrame(new SetLabelText(label, "Drugi okret"), 0);
					anim.addFrame(new DummyFrame(), 20);
					if(pos == LOWER)
						pos = UPPER;
					else
						pos = LOWER;
						
				}
				else
				{
					anim.addFrame(new SetHighlight(label, Color.RED), 0);
					anim.addFrame(new SetLabelText(label, "Treci okret, poligon nije monoton"), 0);
					anim.addFrame(new DummyFrame(), 20);
					monotone = false;
					break;
				}
				dir = ndir;
			}
			anim.addFrame(new DummyFrame(), 5);
			
			lseg = new GLine(current, next);
			lseg.makeRight();
			lseg.setParent(this);
			switch(pos)
			{
			case 0:	// Ne zna se jos
				tempList.add(lseg);
				break;
			case UPPER:	// Gornji
				upperHull.add(lseg);
				lseg.meta1 = UPPER;
				break;
			case LOWER: // Donji
				lowerHull.add(lseg);
				lseg.meta1 = LOWER;
				break;
			}
		}
		if(monotone)
		{
			anim.addFrame(new MoveObject(label, pts.get(0), false), 3);
			anim.addFrame(new SetHighlight(label, new Color(0x00A000)), 0);
			anim.addFrame(new SetLabelText(label, "Poligon je monoton!"), 0);
			
			
			Collections.sort(upperHull, Line.FirstX);
			Collections.sort(lowerHull, Line.FirstX);
			
			upperHull = convertReferences(upperHull);
			lowerHull = convertReferences(lowerHull);
			upperHull.lastElement().meta2 = 1;
			lowerHull.lastElement().meta2 = 1;
			upperHull.firstElement().getP1().meta2 = -1;
			lowerHull.firstElement().getP1().meta2 = -1;
			
			System.out.println("Upper : " + upperHull);
			System.out.println("Lower : " + lowerHull);
		}
		
		anim.addFrame(new DummyFrame(), 30);
		anim.addFrame(new ResetHighlight(label), 0);
		return monotone;
	}
	
	@Override
	public Color getHighlightColor() {
		return null;
	}

	@Override
	public boolean isHighlighted() {
		return false;
	}
	
	public void swapHulls()
	{
		Vector<GLine> tmp = upperHull;
		upperHull = lowerHull;
		lowerHull = tmp;
		for(GLine l : upperHull)
			l.meta1 = UPPER;
		for(GLine l : lowerHull)
			l.meta1 = LOWER;
	}

	
	public static final int AU = 1;
	public static final int AL = 3;
	public static final int BU = 4;
	public static final int BL = 12;
	
	public static final int AUBU = AU | BU;
	public static final int AUBL = AU | BL;
	public static final int ALBU = AL | BU;
	public static final int ALBL = AL | BL;

	public static Vector<GPolygon> intersectMonotone(GPolygon a, GPolygon b,
			TextLabel label, Animation anim, Scene scene, Viewport vp) {
		// Vector<GPolygon> ips = new Vector<GPolygon>();
		// if(!a.getBoundingRect().intersects(b.getBoundingRect())) return ips;

		if (a.upperHull.firstElement().getP1().getY() < b.upperHull
				.firstElement().getP1().getY()) {
			GPolygon tmp = a;
			a = b;
			b = tmp;
		}

		Vector<GLine> lines = new Vector<GLine>();
		lines.addAll(a.upperHull);
		lines.addAll(b.upperHull);
		lines.addAll(a.lowerHull);
		lines.addAll(b.lowerHull);

		System.out.println(lines);

		Collections.sort(lines, Line.FirstX);

		GLine au = null;
		GLine al = null;
		GLine bu = null;
		GLine bl = null;

		// int sau = 0, sal = 0, sbu = 0, sbl = 0;

		// GPolygon npoly = null;
		// Vector<GPoint> npUpper = new Vector<GPoint>();
		// Vector<GPoint> npLower = new Vector<GPoint>();
		Vector<GPoint> intPts = new Vector<GPoint>();

		System.out.println(lines);

		//boolean albl = false;
		//boolean albu = false;
		//boolean aubl = false;
		//boolean aubu = false;

		boolean hotAL = false;
		boolean hotAU = false;
		boolean hotBL = false;
		boolean hotBU = false;

		Vector<GPoint> events = new Vector<GPoint>();
		
		for (GLine line : lines) {
			System.out
					.println("ITER : " + line + "(meta = " + line.meta1 + ")");
			Vector<GPoint> procPts = new Vector<GPoint>();
			
			
			if ((line.getParent() == a && line.meta1 == UPPER)) {
				GPoint np = line.getP1().clone();
				np.meta1 = AU;
				np.meta3 = 1;
				events.add(np.clone());
				procPts.add(np);
				//System.out.println("ADD EVENT!!!");
			}
			if ((line.getParent() == a && line.meta1 == LOWER)) {
				GPoint np = line.getP1().clone();
				np.meta1 = AL;
				np.meta3 = 1;
				events.add(np.clone());
				procPts.add(np);
				//System.out.println("ADD EVENT!!!");
			}
			if ((line.getParent() == b && line.meta1 == UPPER)) {
				GPoint np = line.getP1().clone();
				np.meta1 = BU;
				np.meta3 = 2;
				events.add(np.clone());
				procPts.add(np);
				//System.out.println("ADD EVENT!!!");
			}
			if ((line.getParent() == b && line.meta1 == LOWER)) {
				GPoint np = line.getP1().clone();
				np.meta1 = BL;
				np.meta3 = 2;
				events.add(np.clone());
				procPts.add(np);
				//System.out.println("ADD EVENT!!!");
			}
			
			if (!(al == null || au == null || bu == null || bl == null))
			{
				{
					GPoint is = Line.intersect(al, bl);
					if (is != null) {
						is.meta1 = ALBL;
						//events.add(is);
						procPts.add(is);
					}
				}
				{
					GPoint is = Line.intersect(au, bl);
					if (is != null) {
						is.meta1 = AUBL;
						//events.add(is);
						procPts.add(is);
					}
				}
				{
					GPoint is = Line.intersect(al, bu);
					if (is != null) {
						is.meta1 = ALBU;
						//events.add(is);
						procPts.add(is);
					}
				}
				{
					GPoint is = Line.intersect(au, bu);
					if (is != null) {
						is.meta1 = AUBU;
						//events.add(is);
						procPts.add(is);
					}
				}
			}

			Collections.sort(procPts, PointD.ByX);

			for (GPoint pp : procPts) {
				//boolean wasNull = false;
				anim.addFrame(new SetSweep(vp, pp.getX()), 0);

				switch (pp.meta1) {

				case AU:
				{
					//wasNull = au == null;
					au = line;
					anim.addFrame(new SetHighlight(line, Color.pink), 0);
					anim.addFrame(new MoveObject(label, line.getP1(), false), 0);
					anim.addFrame(new SetLabelText(label,
							"A) Pocetak duzi iz gornjeg omotaca"), 0);
					anim.addFrame(new DummyFrame(), 15);
					//aubl = aubu = true;
					
					if(bu != null && bl != null)
					{
						double y1 = Util.lerpY(bu.getP1(), bu.getP2(), pp.getX());
						double y2 = Util.lerpY(bl.getP1(), bl.getP2(), pp.getX());
						if(pp.getY() >= y2 && pp.getY() <= y1)
						{
							pp.meta1 = -1;
						}
					}

					//events.add(pp.clone());
				}
				break;

				// Prva iz A LOWER
				case AL:
				{
					//wasNull = al == null;
					al = line;
					anim.addFrame(new SetHighlight(line, Color.pink), 0);
					anim.addFrame(new MoveObject(label, line.getP1(), false), 0);
					anim.addFrame(new SetLabelText(label,
							"A) Pocetak duzi iz donjeg omotaca"), 0);
					anim.addFrame(new DummyFrame(), 15);
					//albl = albu = true;

					//events.add(pp.clone());
				}
				break;

				// Prva iz B UPPER
				case BU:
				{
					//wasNull = bu == null;
					bu = line;
					anim.addFrame(new SetHighlight(line, Color.pink), 0);
					anim.addFrame(new MoveObject(label, line.getP1(), false), 0);
					anim.addFrame(new SetLabelText(label,
							"B) Pocetak duzi iz gornjeg omotaca"), 0);
					anim.addFrame(new DummyFrame(), 15);
					//aubu = albu = true;
					
					if(au != null && al != null)
					{
						double y1 = Util.lerpY(au.getP1(), au.getP2(), pp.getX());
						double y2 = Util.lerpY(al.getP1(), al.getP2(), pp.getX());
						if(pp.getY() >= y2 && pp.getY() <= y1)
						{
							pp.meta1 = -1;
						}
					}

					//events.add(pp);
				}
				break;

				// Prva iz B LOWER
				case BL:
				{
					//wasNull = bl == null;
					bl = line;
					anim.addFrame(new SetHighlight(line, Color.pink), 0);
					anim.addFrame(new MoveObject(label, line.getP1(), false), 0);
					anim.addFrame(new SetLabelText(label,
							"B) Pocetak duzi iz donjeg omotaca"), 0);
					anim.addFrame(new DummyFrame(), 15);
					//aubl = albl = true;
					
					//events.add(pp);
				}
				break;
				
				case ALBL: {
					PointD is = Line.intersect(al, bl);
					if (is != null) // Presjek
					{
						GPoint gis = new GPoint(is.getX(), is.getY());
						gis.setVisible(false);
						gis.setColor(Color.green);
						scene.addObject(gis);

						
						anim.addFrame(new SetVisibility(gis, true), 0);
						//if(gis.getX() > events.lastElement().getPosX())
						//{
							anim.addFrame(new MoveObject(label, gis, false), 0);
							anim.addFrame(new SetLabelText(label,
									"Presjek A-L sa B-L"), 0);
							anim.addFrame(new DummyFrame(), 15);
						//}
						//albl = false;

						gis.meta1 = ALBL;
						gis.meta3 = al.isBelowAt(bl, is.getX() + 0.1) ? 1 : 0;
						intPts.add(gis.clone());

						events.add(gis.clone());
					}
				}
					break;

				case ALBU: {
					PointD is = Line.intersect(al, bu);
					System.out.println("BU : " + bu.meta1);
					if (is != null) // Presjek
					{
						GPoint gis = new GPoint(is.getX(), is.getY());
						gis.setVisible(false);
						gis.setColor(Color.green);
						scene.addObject(gis);

					
						anim.addFrame(new SetVisibility(gis, true), 0);
						//if(gis.getX() > events.lastElement().getPosX())
						//{
							anim.addFrame(new MoveObject(label, gis, false), 0);
							anim.addFrame(new SetLabelText(label,
									"Presjek A-L sa B-U"), 0);
							anim.addFrame(new DummyFrame(), 15);
						//}
						//albu = false;

						gis.meta1 = ALBU;
						gis.meta3 = al.isBelowAt(bu, is.getX() + 0.1) ? 1 : 0;
						intPts.add(gis.clone());
						// intPts.lastElement().meta1 = ALBU;

						events.add(gis.clone());
					}
				}
					break;

				case AUBL: {
					PointD is = Line.intersect(au, bl);
					if (is != null) // Presjek
					{
						GPoint gis = new GPoint(is.getX(), is.getY());
						gis.setVisible(false);
						gis.setColor(Color.green);
						scene.addObject(gis);

						
						anim.addFrame(new SetVisibility(gis, true), 0);
						//if(gis.getX() > events.lastElement().getPosX())
						//{
							anim.addFrame(new MoveObject(label, gis, false), 0);
							anim.addFrame(new SetLabelText(label,
									"Presjek A-U sa B-L"), 0);
							anim.addFrame(new DummyFrame(), 15);
						//}
						//aubl = false;

						gis.meta1 = AUBL;
						gis.meta3 = au.isBelowAt(bl, is.getX() + 0.1) ? 1 : 0;
						intPts.add(gis.clone());
						// intPts.lastElement().meta1 = AUBL;

						events.add(gis.clone());
					}
				}
					break;

				case AUBU: {
					PointD is = Line.intersect(au, bu);
					if (is != null) // Presjek
					{
						GPoint gis = new GPoint(is.getX(), is.getY());
						gis.setVisible(false);
						gis.setColor(Color.green);
						scene.addObject(gis);

						
						anim.addFrame(new SetVisibility(gis, true), 0);
						//if(gis.getX() > events.lastElement().getPosX())
						//{
							anim.addFrame(new MoveObject(label, gis, false), 0);
							anim.addFrame(new SetLabelText(label,
									"Presjek A-U sa B-U"), 0);
							anim.addFrame(new DummyFrame(), 15);
						//}
						//aubu = false;

						gis.meta1 = AUBU;
						gis.meta3 = au.isBelowAt(bu, is.getX() + 0.1) ? 1 : 0;
						System.out.println("AUBU isbelow : " + gis.meta3);
						intPts.add(gis.clone());

						events.add(gis.clone());
					}
				}
					break;
				}
			}
			/*
			if(line.meta2 == 1)
			{
				System.out.println("META II");
				anim.addFrame(new MoveObject(label, line.getP2(), false), 0);
				anim.addFrame(new SetSweep(vp, line.getP2().getX()), 0);
				if(line.getParent() == a)
					anim.addFrame(new SetLabelText(label, "Kraj poligona A"), 0);
				else
					anim.addFrame(new SetLabelText(label, "Kraj poligona B"), 0);
				
				anim.addFrame(new DummyFrame(), 20);
			}
			*/
			// }
		}
		
		Collections.sort(events, PointD.ByX);
		

		anim.addFrame(new MoveObject(label, lines.lastElement().getP2(), false), 0);
		anim.addFrame(new SetSweep(vp, lines.lastElement().getP2().getX()), 0);
		anim.addFrame(new SetLabelText(label, "Kraj"), 0);
		anim.addFrame(new DummyFrame(), 30);

		Collections.sort(intPts, PointD.ByX);

		System.out.println("Done!");
		System.out.println("Polypoints : " + intPts.size());

		//anim.clear();
		anim.seekToEnd();
		return composePolygons2(events, label, scene, anim);
	}
	
	private static GPolygon formPolygon(Vector<GPoint> upper, Vector<GPoint> lower)
	{
		GPolygon poly = new GPolygon();
		for(int i = 0; i < upper.size(); ++i)
		{
			poly.addPoint(upper.get(i));
		}
		
		for(int i = lower.size() - 1; i >= 0; --i)
		{
			poly.addPoint(lower.get(i));
		}
		return poly;
	}
	
	private static boolean isSingleLine(int flags)
	{
		//return (flags == AU) || (flags == AL) || (flags == BU) || (flags == BL);
		return (flags < 5) || (flags == 12);
	}
	
	private static boolean isUpper(int flags)
	{
		return (flags == AU) || (flags == BU);
	}
	
	private static boolean isLower(int flags)
	{
		return (flags == AL) || (flags == BL);
	}
	
	private static boolean isA(int flags)
	{
		return (flags == AL) || (flags == AU);
	}
	
	private static boolean isB(int flags)
	{
		return (flags == BL) || (flags == BU);
	}
	
	private static int getOtherPart(int orig, int part)
	{
		if(orig == ALBL)
			if(part == AL)
				return BL;
			else
				return AL;
		
		if(orig == ALBU)
			if(part == AL)
				return BU;
			else
				return AL;
		
		if(orig == AUBL)
			if(part == AU)
				return BL;
			else
				return AU;
		
		if(orig == AUBU)
			if(part == AU)
				return BU;
			else
				return AU;
		
		return 0;
	}
	
	private static int contDown(GPoint p, int carrier)
	{
		if(isA(carrier))
			if(p.meta3 == 0)
				return carrier;
			else
				return getOtherPart(p.meta1, carrier);
		else
			if(p.meta3 == 1)
				return carrier;
			else
				return getOtherPart(p.meta1, carrier);
		
	}
	
	private static int contUp(GPoint p, int carrier)
	{
		if(isA(carrier))
			if(p.meta3 == 1)
				return carrier;
			else
				return getOtherPart(p.meta1, carrier);
		else
			if(p.meta3 == 0)
				return carrier;
			else
				return getOtherPart(p.meta1, carrier);
		
	}
	
	private static int getAPart(int carrier)
	{
		if(carrier == AL || carrier == AU)
			return carrier;
		else if(carrier == ALBU || carrier == ALBL)
			return AL;
		else if(carrier == AUBU || carrier == AUBL)
			return AU;
		else
			return 0;
	}
	
	private static int getBPart(int carrier)
	{
		if(carrier == BL || carrier == BU)
			return carrier;
		else if(carrier == ALBU || carrier == AUBU)
			return BU;
		else if(carrier == ALBL || carrier == AUBL)
			return BL;
		else
			return 0;
	}
	
	private static void pointEvent(GPoint p, String text, TextLabel label, Scene scene, Animation anim)
	{
		anim.addFrame(new MoveObject(label, p, false), 0);
		//anim.addFrame(new SetSweep(vp, lines.lastElement().getP2().getX()), 0);
		anim.addFrame(new SetLabelText(label, text), 0);
		anim.addFrame(new DummyFrame(), 20);
	}
	
	private static boolean isIn(int a, int b)
	{
		if(a == 0) return false;
		
		if(b == ALBL)
			return (a == AL) || (a == BL);
		else if(b == ALBU)
			return (a == AL) || (a == BU);
		else if(b == AUBL)
			return (a == AU) || (a == BL);
		else if(b == AUBU)
			return (a == AU) || (a == BU);
		return false;
	}
	
	private static Vector<GPolygon> composePolygons2(Vector<GPoint> events, TextLabel label, Scene scene, Animation anim)
	{
		Vector<GPolygon> polys = new Vector<GPolygon>();
		Vector<GPoint> upper = new Vector<GPoint>();
		Vector<GPoint> lower = new Vector<GPoint>();
		
		int ucar = 0, lcar = 0;
		
		System.out.println("Event count : " + events.size());
		GPoint last = null;
		for(GPoint p : events)
		{
			if(last != null)
				if(p.equals(last))
					continue;
			last = p;
			
			System.out.println("Event : " + p.meta1 + "; " + p.meta2 + "; " + p.meta3 + " <> " + p);
			/*if(p.meta2 == -1)
			{
				System.out.println("New poly! (meta1 signal)" + p);
				
				if(upper.size() + lower.size() >= 3)
					polys.add(formPolygon(upper, lower));
				
				upper.clear();
				lower.clear();
				
				upper.add(p);
				lower.add(p);
				
				if(p.meta3 == 1)
				{
					ucar = AU;
					lcar = AL;
				}
				else
				{
					ucar = BU;
					lcar = BL;
				}
			}
			else*/
			if(p.meta2 == 1)
			{
				System.out.println("End of poly! (meta2 signal)" + p);
				pointEvent(p, "End of poly! (meta2 signal)" + p, label, scene, anim);
				
				if(upper.size() + lower.size() >= 3)
					polys.add(formPolygon(upper, lower));
				
				ucar = 0;
				lcar = 0;
			}
			else
			{
				if(isSingleLine(p.meta1))
				{
					System.out.println("Single line (" + p.meta1 + ")");
					if(p.meta1 == ucar)
					{
						upper.add(p);
						System.out.println("Tacka dodata u GORNJI omotac");
						//pointEvent(p, "Added to upper " + p.meta1 + " (" + lcar + ")", label, scene, anim);
						pointEvent(p, "Tacka dodana u donji omotac", label, scene, anim);
					}
					if(p.meta1 == lcar)
					{
						lower.add(p);
						System.out.println("Tacka dodana u DONJI omotac");
						//pointEvent(p, "Added to lower " + p.meta1 + " (" + ucar + ")", label, scene, anim);
						pointEvent(p, "Tacka dodana u gornji omotac", label, scene, anim);
					}
				}
				else
				{
					boolean u = false, l = false;
					
					//if((ucar > 0) && (ucar & p.meta1) > 0) // Ucestvuje gornji carrier
					if(isIn(ucar, p.meta1))
					{
						ucar = contDown(p, ucar);
						upper.add(p);
						u = true;
						System.out.println("Continuing upper boundary " + ucar + ";" + p.meta1);
						//pointEvent(p, "Continuing upper boundary U=" + ucar + ";" + p.meta1 + " (L=" + lcar + ")", label, scene, anim);
						pointEvent(p, "Tacka dodana u donji omotac", label, scene, anim);
					}
					//if((lcar > 0) && (lcar & p.meta1) > 0) // Ucestvuje donji carrier
					if(isIn(lcar, p.meta1))
					{
						lcar = contUp(p, lcar);
						lower.add(p);
						l = true;
						System.out.println("Continuing LOWER boundary " + lcar + ";" + p.meta1);
						//pointEvent(p, "Continuing LOWER boundary L=" + lcar + ";" + p.meta1 + " (U=" + ucar + ")", label, scene, anim);
						pointEvent(p, "Tacka dodana u gornji omotac", label, scene, anim);
					}
					
					if(u && l)
					{
						System.out.println("Poly CLOSED!");
						//pointEvent(p, "Poly CLOSED!", label, scene, anim);
						pointEvent(p, "Poligon zatvoren!", label, scene, anim);
						if(upper.size() + lower.size() >= 3)
						{
							polys.add(formPolygon(upper, lower));
							scene.addObject(polys.lastElement());
							polys.lastElement().setVisible(false);
							polys.lastElement().setHighlight(Color.green);
							anim.addFrame(new SetVisibility(polys.lastElement(), true), 5);
						}
						upper.clear(); lower.clear();
						ucar = lcar = 0;
					}
					else if(!(u || l))
					{
						System.out.println("New poly!");
						//pointEvent(p, "New poly!", label, scene, anim);
						pointEvent(p, "Novi poligon!", label, scene, anim);
						if(upper.size() + lower.size() >= 3)
							polys.add(formPolygon(upper, lower));
						upper.clear(); lower.clear();
						
						upper.add(p);
						lower.add(p);
						
						if(p.meta3 == 0) // A je ispod
						{
							lcar = getAPart(p.meta1);
							ucar = getBPart(p.meta1);
							System.out.println("A pocinje ispod");
							//pointEvent(p, "A pocinje ISPOD (U=" + ucar + "; L=" + lcar + ")", label, scene, anim);
							pointEvent(p, "A pocinje ISPOD", label, scene, anim);
						}
						else	// B je ispod
						{
							lcar = getBPart(p.meta1);
							ucar = getAPart(p.meta1);
							System.out.println("B pocinje ispod");
							//pointEvent(p, "B pocinje ISPOD (U=" + ucar + "; L=" + lcar + ")", label, scene, anim);
							pointEvent(p, "B pocinje ISPOD", label, scene, anim);
						}
					}
				}
			}
		}
		
		System.out.println("POLYCOUNT : " + polys.size());
		return polys;
	}
	
	private static Vector<GPolygon> composePolygons(Vector<GPoint> points, Scene scene, Animation anim)
	{
		Vector<GPolygon> polys = new Vector<GPolygon>();
		Vector<GPoint> upper = new Vector<GPoint>();
		Vector<GPoint> lower = new Vector<GPoint>();
		GPolygon cpoly = null;
		int sflag = 0;
		
		for(GPoint p : points)
		{
			if(cpoly == null)
			{
				System.out.println("New poly! " + p);
				cpoly = new GPolygon();
				sflag = p.meta1;
				upper.clear();
				lower.clear();
				
				upper.add(p);
				lower.add(p);
				
				/*
				GPoint cp = p.clone();
				cp.setHighlight(Color.magenta);
				scene.addObject(cp);
				*/
			}
			else
			{
				if(p.meta2 == 1 || (p.meta1 == sflag))
				{
					upper.add(p);
					lower.add(p);
					
					System.out.println("Upper count : " + upper.size());
					System.out.println("Lower count : " + lower.size());
					
					for(int i = 0; i < upper.size(); ++i)
					{
						cpoly.addPoint(upper.get(i));
					}
					
					for(int i = lower.size() - 1; i >= 0; --i)
					{
						cpoly.addPoint(lower.get(i));
					}
					
					polys.add(cpoly);

					cpoly.setVisible(false);
					cpoly.setHighlight(Color.orange);
					scene.addObject(cpoly);
					anim.addFrame(new SetVisibility(cpoly, true), 10);

					cpoly = null;
				}
				else
				{
					if(sflag == ALBU && p.meta1 == BU)
					{
						upper.add(p);
					}
					else if(sflag == ALBU && p.meta1 == AU)
					{
						upper.add(p);
					}
					else if(sflag == ALBU && p.meta1 == AUBU)
					{
						upper.add(p);
					}
					else if(sflag == AUBL && p.meta1 == AU)
					{
						upper.add(p);
					}
					else if(sflag == AUBL && p.meta1 == AUBU)
					{
						upper.add(p);
					}
					else if(sflag == AUBL && p.meta1 == AU)
					{
						upper.add(p);
					}
					
					
					else if(sflag == ALBU && p.meta1 == AL)
					{
						lower.add(p);
					}
					else if(sflag == ALBU && p.meta1 == BL)
					{
						lower.add(p);
					}
					else if(sflag == ALBU && p.meta1 == ALBL)
					{
						lower.add(p);
					}
					else if(sflag == AUBL && p.meta1 == BL)
					{
						lower.add(p);
					}
					else if(sflag == AUBL && p.meta1 == ALBL)
					{
						lower.add(p);
					}
					else if(sflag == AUBL && p.meta1 == AL)
					{
						lower.add(p);
					}
					else
					{
						System.out.println("Missed a point! " + sflag + " " + p.meta1 + " " + p.meta2);
					}
				}
			}
		}
		
		return polys;
	}
	
}
